# Virtual Router Simulator 
#
# Copyright (C) 2009-2010 VRSim Project
# Author: Choonho Son <choonho@kt.com>
# URL: <http://vrsim.googlecode.com>
# For license information, see LICENSE.TXT
#

import uuid
import sys
import os
from socket import socket,  timeout,  AF_INET,  SOCK_STREAM

import subprocess as sub
import telnetlib
import VRSim.Globals as globals

from VRSim.Globals import Adapter

from VRSim.Utils import debug
from VRSim.Node.XML import XML
from VRSim.Node.CiscoDevices import CiscoDevices


class CiscoDomain(XML):
    def __init__(self, nodeid):
        #XML
        XML.__init__(self,  "domain")
        
        self.nodeid = nodeid
        self.type = "Dynamips"
        self.type_list = [ "Dynamips"]
        self.uuid = str(uuid.uuid4())
        self.name = "None"
        
        # Basic resources
        self.memory = "262144"
        self.currrentMemory = "262144"
        
        #self.console = globals.dynamips_console
        #globals.dynamips_console += 1
        
        self.instantID = globals.instantID
        globals.instantID += 1
        
        # Not used
        # Time keeping
        self.clock = None
        self.clock_list = ["utc",  "localtime"]
        
        # Config file
        # HDD disk
        self.cfg = None
        #self.hdd = None
        self.idlepc = None
        
        self.devices = None
        # Nic binding List
        self.nioList = []
        
        
        # dynamips library
        self.host = None
        self.port = None
        self.conn = None
        
    def makeUniqueName(self):
        """ name must globally unique
        """
        userid = globals.GApp.userid
        nodename = globals.GApp.topology.getNodeName(self.nodeid)
        name = "%s_%s" % (userid,nodename) 
        #temp = self.uuid.split("-")
        self.name = name
        return name
    
    def filterToDynamips(self):
        """ change xml to dynamips commands
        """
        pass
     
    """
    def toCMD(self):
        cmd = "dynamips -X "
        cmd += " " + self.hdd
        cmd += " -t " + self.npetype
        cmd += " -M " + self.midplane
        cmd += " -i " + str(self.instantID)
        if self.cfg != "Choose Config File":
            cmd += " -C " + self.cfg
        cmd += " -T " + str(self.console)
        if self.idlepc:
            cmd += " --idle-pc " + self.idlepc
        count = 0
        for slot in self.slots:
            if slot:
                # port
                cmd += " -p " + str(count) + ":" + slot[0]
                # binding
                for index in slot[1:]:
                    string = index.split(" ")
                    port = string[1].split("/")
                    cmd += " -s " + port[0] + ":" + port[1] + ":udp:" + string[2]
            count += 1
            
        return cmd
    """    
          
    def stop(self):
        commands = []
        # stop: vm stop <instance_name>
        commands.append( "vm stop " + str(self.name) )
        # delete: vm delete <instance_name>
        commands.append( "vm delete " + str(self.name) )
        for io in self.nioList:
            commands.append( "nio delete " + io)
        
        # open telnet connection
        if not self.conn:
            self.conn = self.getSocket()
        try:
            for command in commands:
                debug(command)
                self.conn.send(command + "\n")
            tf = True
        except:
            tf = False
            
        if tf == True:
            msg = globals.eventMsg["stop"]
            nmsg = msg % globals.GApp.topology.getNodeName(self.nodeid)
            globals.GApp.mainWindow.NodesLog.addEvent(nmsg)
            return True
        else:
            msg = globals.errorMsg["stop"]
            nmsg = msg % globals.GApp.topology.getNodeName(self.nodeid)
            globals.GApp.mainWindow.NodesLog.addError(nmsg)
            return False 
                
    def getIdlepc(self):
        """ get Idle PC of router
        """
        msg = "getIdlepc called"
        debug(msg)
        commands = []
        # vm get_idle_pc_prop <name> 0
        commands.append("vm get_idle_pc_prop " + str(self.name) + " 0")
        # open telnet connection
        conn = self.getSocket()
        
        try:
            for command in commands:
                debug(command)
                conn.send(command + "\n")
                result = []
                while 1:
                    data = conn.recv(1024)
                    index = data.split("\r\n")
                    for item in index:
                        if item != "":
                            result.append(item)
                    if "100-OK" in result: 
                        result.remove("100-OK")
                        break
                conn.close()
                return result
        except:
            msg = 'Cannot connect dynamips API'
            print msg
            return False
     
    def setIdlepc(self,  value):
        """ set idlepc on router
        """
        msg = "setIdlepc called value(%s)" % value
        debug(msg)
        command = "vm set_idle_pc_online " + str(self.name) + " 0 " + value + "\n"
        # open telnet connection
        print command
        conn = self.getSocket()
        conn.send(command)
        #print conn.recv(1024)
        conn.close()
        return True
        
    def getSocket(self):
        conn = socket(AF_INET,  SOCK_STREAM )
        #conn.setblocking(0)
        #conn.settimeout(int(timeout))
        print "connecting ..." + self.host,  self.port
        conn.connect( (self.host,  self.port) )
        return conn
        
        
    def openConsole(self):
        if sys.platform.startswith('win'):
            # windows platform
            path = globals.TERMINAL
            path_split = path.split("/")
                
            #os.chdir(base_dir)
            term = path_split[-1]
            npath = unicode(path).encode(globals.ENCODING)
                
                
            if term == "putty.exe":
                # putty command
                cmd = "%s telnet://%s:%s/" % (npath,  self.devices.console_ip,  self.devices.console)
            elif term == "ttermpro.exe":
                # teraterm command
                cmd = "%s telnet://%s:%s  /T=0 /W=%s" % (npath,  self.devices.console_ip,  self.devices.console,  self.hostname)
            else:
                cmd = "%s" % (path)
                
            sub.Popen(cmd,  shell=False)
        elif sys.platform.startswith('linux'):
            # linux platform
            cmd = "telnet %s %s" % (self.devices.console_ip,  self.devices.console)
            sub.Popen("xterm -T " + self.hostname + " -e '" + cmd + "' >  /dev/null 2>&1 &",  shell = True,  close_fds=True)
        return
        
    def getXML(self):
        domain = self.xml.createElement("domain")
        domain.setAttribute("type",  str(self.type))
        name = self.xml.createElement("name")
        #nameText = self.xml.createTextNode(str(self.hostname))
        #nameText = self.xml.createTextNode(str(self.name))
        nameText = self.xml.createTextNode(str(self.makeUniqueName()))
        name.appendChild(nameText)
        uuid = self.xml.createElement("uuid")
        uuidText = self.xml.createTextNode(self.uuid)
        uuid.appendChild(uuidText)
        memory = self.xml.createElement("memory")
        memoryText = self.xml.createTextNode(str(self.memory))
        memory.appendChild(memoryText)
        vcpu = self.xml.createElement("vcpu")
        vcpu.setAttribute("npe",  str(self.npetype))
        vcpu.setAttribute("midplane",  str(self.midplane))
        vcpuText = self.xml.createTextNode(str(self.vcpu))
        vcpu.appendChild(vcpuText)

        domain.appendChild(name)
        domain.appendChild(uuid)
        domain.appendChild(memory)
        domain.appendChild(vcpu)
        if self.cfg:
            cfg = self.xml.createElement("config")
            cfg.setAttribute("file",  self.cfg)
            domain.appendChild(cfg)
        
        #clock
        clock = self.xml.createElement("clock")
        clock.setAttribute("offset",  str(self.clock))
        
        #devices
        devices = self.devices.getXML()
        domain.appendChild(devices)
        
        # interfaces
        return domain
    
    def setXML(self,  domain):
        """ update members by xml elements
        """
        #<domain type='kvm'>            self.type
        # <name>routerA</name>      self.name
        # <uuid>xxx</uuid>                self.uuid
        # <memory>xxx</memory>    self.memory
        # <vcpu>1</vcpu>                  self.vcpu
        # <config file='/data/c7200.cfg'/>
        self.type = domain.getAttribute("type")
        node_name = domain.getElementsByTagName("name")[0]
        self.name = node_name.firstChild.data
        node_uuid = domain.getElementsByTagName("uuid")[0]
        self.uuid = node_uuid.firstChild.data
        node_memory = domain.getElementsByTagName("memory")[0]
        self.memory = node_memory.firstChild.data
        node_vcpu = domain.getElementsByTagName("vcpu")[0]
        self.vcpu = node_vcpu.firstChild.data
        
        # config
        node_cfg = domain.getElementsByTagName("config")
        if node_cfg:
            self.cfg = node_cfg[0].getAttribute("file")
        
        # devices
        node_devices = domain.getElementsByTagName("devices")[0]
        self.devices.setXML(node_devices)
        
        
        
